use axum::{
    extract::{DefaultBodyLimit, Multipart},
    routing::{get, post},
    Json, Router,
};
use serde_json::{json, Value};
use tower_http::services::ServeDir;

use std::fs;
use std::net::SocketAddr;

use crate::config;

#[tokio::main]
pub async fn start() {
    let app = Router::new()
        .nest_service("/", ServeDir::new("assets"))
        .route("/api/apps", get(root))
        .route("/api/component_class", get(get_component_class))
        .route("/api/add_component_class", post(add_component_class))
        .layer(DefaultBodyLimit::disable());
    let addr = SocketAddr::from(([127, 0, 0, 1], 1644));
    println!("mmerge ui service launched on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn root() -> Json<Value> {
    let madp_location = get_madp_location();
    let app_json_str = match fs::read_to_string(format!(
        "{}/data/csii-shared/apps/_list.json",
        madp_location
    )) {
        Ok(json_str) => json_str.clone(),
        Err(_) => return Json(json!({"code": -1, "data": "未找到应用配置文件"})),
    };
    // &app_json_strJson
    let app_json: Value = match serde_json::from_str(&app_json_str) {
        Ok(json_str) => json_str,
        Err(_) => return Json(json!({"code": -1, "data": "加载配置出错"})),
    };
    Json(json!({"code": 100, "data": app_json}))
}

async fn get_component_class() -> Json<Value> {
    let madp_location = get_madp_location();
    let com_json_str = match fs::read_to_string(format!(
        "{}/data/csii-shared/defaultTheme/admin/components/config.schema.json",
        madp_location
    )) {
        Ok(json_str) => json_str.clone(),
        Err(_) => return Json(json!({"code": -1, "data": "未找到应用配置文件"})),
    };
    let com_json: Value = match serde_json::from_str(&com_json_str) {
        Ok(json_str) => json_str,
        Err(_) => return Json(json!({"code": -1, "data": "加载配置出错"})),
    };
    Json(json!({"code": 100, "data": com_json}))
}
async fn add_component_class(mut multipart: Multipart) -> Json<Value> {
    let madp_location = get_madp_location();
    while let Some(file) = multipart.next_field().await.unwrap() {
        let field = file.name().unwrap().to_string();
        if field == String::from("file") {
            let filename = file.file_name().unwrap().to_string();
            let content = file.text().await.unwrap().to_string();
            // 保存文件
            match tokio::fs::write(
                format!(
                    "{}/data/csii-shared/defaultTheme/admin/components/{}",
                    madp_location, filename
                ),
                &content,
            )
            .await
            .map_err(|err| err.to_string())
            {
                Ok(_) => (),
                Err(_) => return Json(json!({"code": -1, "data": "保存文件失败"})),
            }
        } else if field == String::from("config") {
            let content = file.text().await.unwrap().to_string();
            // 保存文件
            match tokio::fs::write(
                format!(
                    "{}/data/csii-shared/defaultTheme/admin/components/config.schema.json",
                    madp_location
                ),
                &content,
            )
            .await
            .map_err(|err| err.to_string())
            {
                Ok(_) => (),
                Err(_) => return Json(json!({"code": -1, "data": "保存文件失败"})),
            }
        }
    }
    Json(json!({"code": 100, "data": "ok"}))
}
// async fn get_component_instance(Query(params): Query<Params>) -> Json<Value> {
//     // format!("{:?}", params.id)
//     let app_id = match params.id {
//         Some(id) => id,
//         None(_) => return Json(json!({"code": -1, "data": "加载配置出错"}))
//     };
// }

// #[derive(Debug, Deserialize)]
// #[allow(dead_code)]
// struct Params {
//     #[serde(default, deserialize_with = "empty_string_as_none")]
//     id: Option<String>,
// }
fn get_madp_location() -> String {
    let madp_config_str = match fs::read_to_string("./config.toml") {
        Ok(str) => str,
        Err(_) => config::DEFAULT_MADP_CONFIG.to_string(),
    };
    let config: config::MadpConfig = match toml::from_str(&madp_config_str) {
        Ok(cfg) => cfg,
        Err(err) => panic!("err: {}", err),
    };
    config.madp_location
}
// /// Serde deserialization decorator to map empty Strings to None,
// fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
// where
//     D: Deserializer<'de>,
//     T: FromStr,
//     T::Err: fmt::Display,
// {
//     let opt = Option::<String>::deserialize(de)?;
//     match opt.as_deref() {
//         None | Some("") => Ok(None),
//         Some(s) => FromStr::from_str(s).map_err(de::Error::custom).map(Some),
//     }
// }
